class AuthD::Request
	IPC::JSON.message ModUser, 6 do
		property user       : UserID? = nil
		property admin      : Bool?   = nil
		property password   : String? = nil
		property email      : String? = nil

		def initialize(@user, @admin, @password, @email)
		end

		def to_s(io : IO)
			super io
			io << " (user: #{@user}, admin: #{@admin})"
		end

		def handle(authd : AuthD::Service, fd : Int32)
			logged_user = authd.get_logged_user_full? fd
			return Response::ErrorMustBeAuthenticated.new if logged_user.nil?

			# The user will be modified, we should get a COPY of the user.
			user = if u = @user
				logged_user.assert_permission("authd", "*", User::PermissionLevel::Edit)
				authd.user? u
			else
				logged_user
			end
			return Response::ErrorUserNotFound.new if user.nil?

			cloned_user : AuthD::User = user.clone

			# Only an admin can uprank or downrank someone.
			if admin = @admin
				logged_user.assert_permission("authd", "*", User::PermissionLevel::Admin)
				cloned_user.admin = admin
			end

			@password.try do |s|
				cloned_user.password_hash = authd.hash_password s
			end

			# In case of a new email address:
			# 1. the new address is stored as "pending_email"
			# 2. the new address has to be validated before being used as primary email address
			if email = @email
				# Verify the email address isn't already in the database.
				if authd.users_per_email.get? Base64.encode(email).chomp
					return Response::ErrorEmailAddressAlreadyUsed.new
				end
				cloned_user.contact.pending_email = email
				cloned_user.contact.new_activation_key

				begin
					u_login            = cloned_user.login
					u_email            = cloned_user.contact.pending_email.not_nil!
					u_activation_token = cloned_user.contact.activation_key.not_nil!

					# Once the user is created and stored, we try to contact him.
					send_activation_token authd, u_login, u_email, u_activation_token
				rescue e
					Baguette::Log.error "mailer: #{e}"
					return Response::ErrorCannotContactUser.new
				end
			end

			begin
				authd.users_per_uid.update cloned_user.uid.to_s, cloned_user
			rescue e
				return Response::Error.new "could not update the user (email may already be used)"
			end

			Response::UserEdited.new cloned_user.uid
		end
	end
	AuthD.requests << ModUser
end
